package com.ruicar.afs.cloud.contract.gateway.components;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import com.ruicar.afs.cloud.common.core.util.SpringContextHolder;
import com.ruicar.afs.cloud.contract.gateway.beans.ApiDefine;
import com.ruicar.afs.cloud.contract.gateway.beans.GateWayResponse;
import com.ruicar.afs.cloud.contract.gateway.beans.SystemDefine;
import com.ruicar.afs.cloud.contract.gateway.entity.GateWayApiMapping;
import com.ruicar.afs.cloud.contract.gateway.entity.GateWayOutDataMapping;
import com.ruicar.afs.cloud.contract.gateway.entity.GateWaySystemMapping;
import com.ruicar.afs.cloud.contract.gateway.entity.GateWaySystemParamInMapping;
import com.ruicar.afs.cloud.contract.gateway.enums.ProcessorName;
import com.ruicar.afs.cloud.contract.gateway.processor.ProcessorHelper;
import com.ruicar.afs.cloud.contract.gateway.processor.api.ApiProcessor;
import com.ruicar.afs.cloud.contract.gateway.processor.result.ResultConvertProcessor;
import com.ruicar.afs.cloud.contract.gateway.processor.value.ValueProcessor;
import com.ruicar.afs.cloud.contract.gateway.service.GateWayApiMappingService;
import com.ruicar.afs.cloud.contract.gateway.service.GateWayOutDataMappingService;
import com.ruicar.afs.cloud.contract.gateway.service.GateWaySystemMappingService;
import com.ruicar.afs.cloud.contract.gateway.service.GateWaySystemParamInMappingService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * The type ProcessorCache
 * <p>Description: </p>
 *
 * @author Fzero
 * @version 1.0
 * @date Created on 2020.07.20 21:17:41
 * @since 1.0
 */
@Component
@AllArgsConstructor
@Slf4j
public class ProcessorCache {
    /**
     * Api processor map
     * <p>Description: </p>
     */
    private static final Map<ProcessorName, ApiProcessor> API_PROCESSOR_MAP = new HashMap<>();
    /**
     * Value processor map
     * <p>Description: </p>
     */
    private static final Map<ProcessorName, ValueProcessor> VALUE_PROCESSOR_MAP = new HashMap<>();


    private static final Map<String, ResultConvertProcessor> RESULT_CONVERT_PROCESSOR_MAP = new HashMap<>();
    /**
     * Api processor list
     * <p>Description: </p>
     */
    private final List<ApiProcessor> apiProcessorList;
    /**
     * Value processor list
     * <p>Description: </p>
     */
    private final List<ValueProcessor> valueProcessorList;

    private final List<ResultConvertProcessor> resultConvertProcessors;

    /**
     * Init processor
     */
    @PostConstruct
    public void initProcessor(){
        API_PROCESSOR_MAP.putAll(apiProcessorList
                .stream()
                .collect(Collectors.toMap(ApiProcessor::processName, Function.identity()))
        );

        VALUE_PROCESSOR_MAP.putAll(valueProcessorList
                .stream()
                .collect(Collectors.toMap(ValueProcessor::processName, Function.identity()))
        );
        RESULT_CONVERT_PROCESSOR_MAP.putAll(resultConvertProcessors.stream()
                .collect(Collectors.toMap(ResultConvertProcessor::key, Function.identity())));
    }

    /**
     * Get api processor api processor
     *
     * @param processorName processor name
     * @return the api processor
     */
    public static ApiProcessor getApiProcessor(ProcessorName processorName){
        return API_PROCESSOR_MAP.getOrDefault(processorName, UN_KNOW_API_PROCESSOR);
    }

    /**
     * Get value processor value processor
     *
     * @param processorName processor name
     * @return the value processor
     */
    public static ValueProcessor getValueProcessor(ProcessorName processorName){
        return VALUE_PROCESSOR_MAP.getOrDefault(processorName,UN_KNOW_VALUE_PROCESSOR);
    }

    public static ResultConvertProcessor getResultProcessor(String resultConvertName){
        return RESULT_CONVERT_PROCESSOR_MAP.getOrDefault(resultConvertName,UN_KNOW_RESULT_PROCESSOR);
    }

    /**
     * Un know api processor
     * <p>Description: </p>
     */
    private static final ApiProcessor UN_KNOW_API_PROCESSOR = new ApiProcessor() {
        @Override
        public ProcessorName processName() {
            return ProcessorName.NONE;
        }

        @Override
        public GateWayResponse process(JSON params, ApiDefine apiDefine) {
            return new GateWayResponse(HttpStatus.NOT_FOUND, MediaType.APPLICATION_JSON, JSONObject.toJSONString(IResponse.fail("配置处理器未找到")));
        }
    };

    private static final ResultConvertProcessor UN_KNOW_RESULT_PROCESSOR = new ResultConvertProcessor() {

        @Override
        public void convert(SystemDefine systemDefine, cn.hutool.json.JSONObject jsonObject) {

        }

        @Override
        public String key() {
            return "default";
        }
    };

    /**
     * Un know value processor
     * <p>Description: </p>
     */
    private static final ValueProcessor UN_KNOW_VALUE_PROCESSOR = new ValueProcessor<Object,Object>() {
        @Override
        public ProcessorName processName() {
            return ProcessorName.NONE;
        }

        @Override
        public Object process(Object sourceValue, Object defaultValue) {
            return sourceValue==null?defaultValue:sourceValue;
        }
    };

    /**
     * Get all gate way mapping list
     *
     * @return the list
     */
    public static List<GateWayApiMapping> getAllGateWayMapping(){
        return SpringContextHolder.getBean(GateWayApiMappingService.class).list();
    }


    /**
     * Get api define api define
     *
     * @param apiMapping api mapping
     * @return the api define
     */
    public static ApiDefine getApiDefine(GateWayApiMapping apiMapping){

        ApiDefine apiDefine = new ApiDefine();
        apiDefine.setGateWayApiMapping(apiMapping);
        List<GateWaySystemMapping> gateWaySystemMappings = SpringContextHolder.getBean(GateWaySystemMappingService.class).list(Wrappers.<GateWaySystemMapping>lambdaQuery().eq(GateWaySystemMapping::getApiId,apiMapping.getId()));
        List<GateWaySystemParamInMapping> gateWaySystemParamInMappings= SpringContextHolder.getBean(GateWaySystemParamInMappingService.class)
                .list(Wrappers.<GateWaySystemParamInMapping>lambdaQuery().eq(GateWaySystemParamInMapping::getApiId,apiMapping.getId()));
        List<GateWayOutDataMapping> gateWayOutDataMappings = SpringContextHolder.getBean(GateWayOutDataMappingService.class)
                .list(Wrappers.<GateWayOutDataMapping>lambdaQuery().eq(GateWayOutDataMapping::getApiId,apiMapping.getId()));
        gateWaySystemMappings.stream().forEach(gateWaySystemMapping -> {
            gateWaySystemMapping.setTargetUrl(genRequestUri(gateWaySystemMapping.getTargetUrl()));
            if(!gateWaySystemMapping.getTargetUrl().startsWith("lb://")&&!gateWaySystemMapping.getTargetUrl().startsWith("http://")&&!gateWaySystemMapping.getTargetUrl().startsWith("https://")){
                log.warn("ID是[{}]目标系统配置错误请求协议未知====>[{}]",gateWaySystemMapping.getId(),gateWaySystemMapping.getTargetUrl());
            }else {
                if (!apiDefine.getTypeListMap().containsKey(gateWaySystemMapping.getSystemType())) {
                    apiDefine.getTypeListMap().put(gateWaySystemMapping.getSystemType(), new ArrayList<>());
                }
                SystemDefine systemDefine = new SystemDefine();
                systemDefine.setGateWaySystemMapping(gateWaySystemMapping);
                systemDefine.setParamInMappings(gateWaySystemParamInMappings.stream().filter(param -> gateWaySystemMapping.getId().equals(param.getSystemId())).collect(Collectors.toList()));
                systemDefine.setOutDataMappings(gateWayOutDataMappings.stream().filter(param -> gateWaySystemMapping.getId().equals(param.getSystemId())).collect(Collectors.toList()));
                apiDefine.getTypeListMap().get(gateWaySystemMapping.getSystemType()).add(systemDefine);
            }
        });
        Assert.isTrue(!apiDefine.getTypeListMap().isEmpty(),"API未配置目标系统");
        return apiDefine;
    }

    public static String genRequestUri(String requestUri){
        StringBuffer stringBuffer = new StringBuffer();
        int pos=0;
        while(pos<requestUri.length()){
            if(requestUri.indexOf("${",pos)<0){
                stringBuffer.append(requestUri.substring(pos));
                break;
            }
            int lastPos = pos;
            pos = requestUri.indexOf("${",lastPos);
            stringBuffer.append(requestUri.substring(lastPos,pos));
            lastPos = pos;
            pos = requestUri.indexOf("}",lastPos+2);
            String paramPath = requestUri.substring(lastPos+2,pos);
            String tempValue =SpringContextHolder.getApplicationContext().getEnvironment().getProperty(paramPath,"${"+paramPath+"}");
            stringBuffer.append(tempValue);
            pos+=1;
        }
        return stringBuffer.toString();
    }
}
